import { randomUUID } from '../../../mapUtils/RandomUtil';

var CacheFeatures = {};

/**
 * 图形绘制捕捉工具
 */
class SnapUtil {
  constructor(_map) {
    this.map = _map;
    // 辅助样式
    this.snapBufferWidth = 1;
    this.snapBufferOpacity = 0;
    this.snapBufferCursorWidth = 15;
    this.snappedFeature = null;
    this._mouseoverHandler = this.mouseoverHandler.bind(this);
    this._mouseoutHandler = this.mouseoutHandler.bind(this);
    this.initLayer();
  }

  /**
   * 初始化捕捉图层
   */
  initLayer() {
    // 需要捕捉的数据源
    if(!this.map.getSource('snap_buffer_source')) {
      this.map.addSource('snap_buffer_source', {
        type: 'geojson',
        data: {
          type: 'FeatureCollection',
          features: []
        }
      });
    }
    // 辅助捕捉数据源
    if(!this.map.getSource('_snap_vertex')) {
      this.map.addSource('_snap_vertex', {
        type: 'geojson',
        data: {
          type: 'FeatureCollection',
          features: []
        }
      });
    }
    // 需要捕捉的线图层
    if(!this.map.getLayer('snap_buffer_line_layer')) {
      this.map.addLayer({
        id: 'snap_buffer_line_layer',
        type: 'line',
        source: 'snap_buffer_source',
        filter: ['all', ['==', '$type', 'LineString']],
        layout: {
          'line-cap': 'round',
          'line-join': 'round'
        },
        paint: {
          'line-color': '#ff0000',
          'line-width': this.snapBufferWidth,
          'line-opacity': this.snapBufferOpacity
        }
      });
    }
    // 需要捕捉的点图层
    if(!this.map.getLayer('snap_buffer_circle_layer')) {
      this.map.addLayer({
        id: 'snap_buffer_circle_layer',
        type: 'circle',
        source: 'snap_buffer_source',
        filter: ['all', ['==', '$type', 'Point']],
        paint: {
          'circle-radius': this.snapBufferWidth,
          'circle-color': '#ff0000',
          'circle-opacity': this.snapBufferOpacity
        }
      });
    }
    // 辅助捕捉图层
    if(!this.map.getLayer('_snap_vertex')) {
      this.map.addLayer({
        id: '_snap_vertex',
        type: 'circle',
        source: '_snap_vertex',
        paint: {
          'circle-color': 'transparent',
          'circle-radius': 5,
          'circle-stroke-width': 3,
          'circle-stroke-color': 'orange'
        }
      });
    }
  }

  /**
   * 开始捕捉
   */
  start() {
    this.map.on('mousemove', this._mouseoverHandler);
    this.map.on('mouseout', this._mouseoutHandler);
    this.moveSnapLayersToTop();
  }

  /**
   * 停止捕捉
   */
  stop() {
    this.map.off('mousemove', this._mouseoverHandler);
    this.map.off('mouseout', this._mouseoutHandler);
    this.setSnapVertex([]);
  }

  /**
   * 鼠标移入事件
   * @param {*} e 事件对象
   */
  mouseoverHandler(e) {
    // console.log("mousemove", e);
    let northeastPoint = {
      x: e.point.x + this.snapBufferCursorWidth,
      y: e.point.y + this.snapBufferCursorWidth
    };
    let southwestPoint = {
      x: e.point.x - this.snapBufferCursorWidth,
      y: e.point.y - this.snapBufferCursorWidth
    };
    let points = [southwestPoint, northeastPoint];
    // console.log(points);
    var features = this.map.queryRenderedFeatures(points, {
      layers: ['snap_buffer_line_layer', 'snap_buffer_circle_layer']
    });
    // 使用原本的geometry
    features.forEach((feature) => {
      feature._geometry = JSON.parse(feature.properties.geometry);
      feature.geometry = JSON.parse(feature.properties.geometry);
    });
    let pointFeature, lineFeature;
    let pointFeatures = [],
      lineFeatures = [];
    features.forEach((feature) => {
      if (feature.layer.type === 'circle') {
        pointFeatures.push(feature);
      } else if (feature.layer.type === 'line') {
        lineFeatures.push(feature);
      }
    });
    if (pointFeatures.length === 1) {
      pointFeature = pointFeatures[0];
    } else if (pointFeatures.length > 1) {
      // 如果捕捉到多个点，则取第一个有oid的点
      let temp = pointFeatures.find((feature) => feature.properties && feature.properties.oid);
      pointFeature = temp ? temp : pointFeatures[0];
    }
    if (lineFeatures.length === 1) {
      lineFeature = lineFeatures[0];
    } else if (lineFeatures.length > 1) {
      // 如果捕捉到多条线，则取第一条有oid的线
      let temp = lineFeatures.find((feature) => feature.properties && feature.properties.oid);
      lineFeature = temp ? temp : lineFeatures[0];
    }
    this.snappedFeature = pointFeature || lineFeature;
  }

  /**
   * 鼠标移出事件
   */
  mouseoutHandler() {
    this.snappedFeature = null;
  }

  /**
   * 捕捉方法
   * @param {Object} lngLat 当前位置坐标
   */
  snap(lngLat) {
    // console.log(JSON.stringify(lngLat));
    var point = this.getNearestPoint(lngLat);
    if (point) {
      this.setSnapVertex([turf.point(point)]);
      // console.log("snappedFeature", this.snappedFeature);
      var ownerid = this.snappedFeature.properties && this.snappedFeature.properties.owner;
      // console.log(this.getSnapOwner(ownerid));
      return {
        lng: point[0],
        lat: point[1],
        owner: ownerid,
        ownerFeature: ownerid ? this.getSnapOwner(ownerid) : null
      };
    }
    this.setSnapVertex([]);
    return lngLat;
  }

  /**
   * 加载捕捉到的点
   */
  setSnapVertex(features) {
    this.map.getSource('_snap_vertex').setData(turf.featureCollection(features));
  }

  /**
   * 获取捕捉点坐标
   * @param {*} lngLat 当前位置坐标
   */
  getNearestPoint(lngLat) {
    // 已找到捕捉的元素
    if (this.snappedFeature) {
      if (turf.getType(this.snappedFeature) === 'Point') {
        return turf.getCoord(this.snappedFeature);
      } else if (turf.getType(this.snappedFeature) === 'LineString') {
        var point = turf.nearestPointOnLine(this.snappedFeature, turf.point([lngLat.lng, lngLat.lat]));
        return turf.getCoord(point);
      }
    }
  }

  /**
   * 加载待捕捉对象
   * @param {features} snapSource 捕捉对象
   * @param {*} filter 过滤条件
   */
  initSnapSource(snapSource, filter) {
    var features;
    if (typeof snapSource === 'function') {
      features = snapSource();
    } else if (snapSource.type === 'FeatureCollection') {
      features = snapSource.features;
    } else {
      features = snapSource;
    }
    // init caches
    CacheFeatures = {};
    let pointFeatures = [];
    let lineFeatures = [];
    // 只捕捉点图层或者线图层
    if (filter && filter.type === 'point') {
      pointFeatures = this.getPointFeatures(features);
    } else if (filter && filter.type === 'linestring') {
      lineFeatures = this.getLineFeatures(features);
    } else {
      pointFeatures = this.getPointFeatures(features);
      lineFeatures = this.getLineFeatures(features);
    }
    this.map.getSource('snap_buffer_source').setData(turf.featureCollection(pointFeatures.concat(lineFeatures)));
  }

  /**
   * 加载待捕捉点对象
   * @param {features} features 点对象集合
   */
  getPointFeatures(features) {
    var result = [];
    features.forEach((feature) => {
      var type = turf.getType(feature);
      switch (type) {
        case 'Point':
          var point = turf.point(turf.getCoords(feature), feature.properties);
          this.appendCacheFeature(point, feature);
          result.push(point);
          break;
        case 'LineString':
          var coords = turf.getCoords(feature);
          coords.forEach((coord) => {
            let pointForLine = turf.point(coord);
            this.appendCacheFeature(pointForLine, feature);
            result.push(pointForLine);
          });
          break;
        case 'Polygon':
          coords = turf.getCoords(feature).flat();
          coords.forEach((coord) => {
            let pointForPolygon = turf.point(coord);
            this.appendCacheFeature(pointForPolygon, feature);
            result.push(pointForPolygon);
          });
          break;
        default:
          break;
      }
    });
    return result;
  }

  /**
   * 加载待捕捉线对象
   * @param {features} features 线对象集合
   */
  getLineFeatures(features) {
    var result = [];
    features.forEach((feature) => {
      var type = turf.getType(feature);
      switch (type) {
        case 'Point':
          break;
        case 'LineString':
          this.appendCacheFeature(feature, feature);
          result.push(feature);
          break;
        case 'Polygon':
          var lines = turf.lineSegment(feature).features;
          lines.forEach((line) => {
            var _line = JSON.parse(JSON.stringify(line));
            this.appendCacheFeature(_line, feature);
            result.push(_line);
          });
          break;
        default:
          break;
      }
    });
    return result;
  }

  /**
   * 缓存待捕捉对象
   * @param {feature} snapFeature 待捕捉对象集合
   * @param {feature} ownerFeature 所属图形
   */
  appendCacheFeature(snapFeature, ownerFeature) {
    var featureid = randomUUID();
    snapFeature.properties.owner = featureid;
    snapFeature.properties.geometry = snapFeature.geometry;
    CacheFeatures[featureid] = ownerFeature;
  }

  /**
   * 获取捕捉对象所属图形
   * @param {String} ownerid
   */
  getSnapOwner(ownerid) {
    return CacheFeatures[ownerid];
  }

  /**
   * 将绘制的图层移到地图最上层
   */
  moveSnapLayersToTop() {
    let glDrawLayers = ['snap_buffer_line_layer', 'snap_buffer_circle_layer', '_snap_vertex'];
    glDrawLayers.forEach((layer) => {
      this.map.moveLayer(layer);
    });
  }
}

export default SnapUtil;
